webpack
根据配置初始化参数,加载插件,实例化 webpack 对象,调用 run 方法开始编译,识别所有入口文件,然后根据入口文件 loader 递归编译模块并构建依赖图谱,打包成 chunk,输出到指定路径
多进程构建,代码压缩,缓存,exclude,include 缩小搜索/构建范围
初始化
pnpm install webpack webpack-cli webpack-dev-server --save-dev
webpack --progress --config build/webpack.prod.js
webpack --watch
webpack serve --open
webpack 优化
构建时间优化
多进程打包 thread-loader:将thread-loader放在费资源loader前面
缓存cache-loader二次构建速度提升: 放在其他loaders前面,将缓存后面的loaders
快速定位位错误位置source-map: devtool中配置
热更新插件HotModuleReplacementPlugin
构建体积分析webpack-bundle-analyzer插件:可视化分析模块打包后的大小,gzip压缩后的大小,模块依赖关系
打包体积优化
单独提取css样式文件MiniCssExtractPlugin
css压缩插件css-minimizer-webpack-plugin
js压缩插件terser-webpack-plugin
html压缩html-webpack-plugin
图片压缩image-webpack-loader
无用代码删除tree-sharking: webpack5生产模式默认开启,babel不能转译成es6一下的代码,要支持es6 module才有效
用户体验优化
模块懒加载splitChunksPlugin:首屏请求所有资源,单页应用首屏加载慢,分块按需加载,提升首屏性能
gzip压缩插件 CompressionWebpackPlugin :后端还得设置,运输过程压缩,减少传输时间,客户端解析时间开销增加,Accept-Encoding:gzip来标识对压缩的支持
常见配置
入口文件生成 initial(初始化) chunk, 包含入口起点指定的所有模块及其依赖项。 non-initial 是可以延迟加载的块。可能会出现在使用 动态导入(dynamic imports) 或者 SplitChunksPlugin 时。
// 异步(动态)导入指定chunk名称
import(
/* webpackChunkName: "app" */
'./app.jsx'
).then((App) => {
ReactDOM.render(<App />, root);
});
module.exports = (env) => {}
module.exports = {
context: Path.resolve(__dirname, '../frontend'),
target: 'node',
// 配置source-map
devtool: dev: 'eval-source-map', "eval"
pro: "source-map" "eval-cheap-module-source-map"
// 入口
entry: { // ['', '', ''] ''
index: {
filename: 指定输出output文件名
import: './src/index.js', 启动时加载的模块
runtime: '', // 同个入口不能与dependOn共存,运行时chunk名称
dependOn: 'lodash' // 依赖的入口,在入口加载前先加载
},
lodash: 'lodash'
},
// 输出
output: { // 常用占位符 文件hash:[contenthash] chunkId:[id] 入口文件名(默认main):[name]
path: __dirname + "/public",
pathinfo: false, // 不携带路径信息
// 静态导入命名
filename: "[name].bundle.js"
// 动态导入命名
chunkFilename: "[id].[contenthash].js"
},
mode:"production", // development
// 本地服务器
devServer: {
static: './dist', // 本地服务器所加载的页面所在的目录 ['', '']
historyApiFallback: true, // 不跳转
hot: true, // 热更新
port:"8080" // 监听端口
host: '' // 默认'localhost'
open: '' // 自动打开浏览器预览,默认为 false,可以设置为 'true' 或指定浏览器名称,如 'Chrome'。
compress: '' // 启用 gzip 压缩,可以提高文件传输效率。
overlay: '' // 在浏览器窗口中显示编译错误或警告信息。
client: {
logging: 'info', // 设置日志级别
progress: true, // 显示编译进度条
overlay: { // 配置错误覆盖层
errors: true,
warnings: false,
timeout: 2000, // 错误覆盖层2秒后自动隐藏
},
reconnect: { // 配置WebSocket断线重连
delay: 2000,
retries: 3, // 尝试重连3次
},
webSocketURL: {
hostname: 'localhost',
pathname: '/ws',
port: 3001,
},
},
proxy: {
'/api': 'http://localhost:8080', // 代理API请求到后端服务器
}
},
// 模块切分
optimization:{
usedExports: true, // tree shaking 生产模式默认开启
runtimeChunk: 'single', // 运行时chunk单独分包
splitChunks:{
chunks: 'async', // 仅分包入口文件及其依赖 initial; all 表示所有模块,动态导入和静态; async 只分包异步chunk
minSize: 20000, // 最小分包大小,小于该值与原chunk合并
minRemainingSize: 0, // 最小剩余chunk大小
minChunks: 1, // 最小引用次数
maxAsyncRequests: 30, // 最大异步请求数
maxInitialRequests: 30, // 最大初始请求数
enforceSizeThreshold: 50000, // 超过该值强制拆分
cacheGroups: { // 分包策略
defaultVendors: {
test: /[\\/]node_modules[\\/]/, // 匹配node_modules中的文件
priority: -10, // 优先级
reuseExistingChunk: true, // 是否复用该chunk(如果被引用则使用,而不是重复打包)
},
default: {
minChunks: 2, // 至少被引用两次
priority: -20, // 优先级
reuseExistingChunk: true, // 是否复用该chunk(如果被引用则使用,而不是重复打包)
},
}
}
}
}
loaders
webpack 只能处理 js,json 文件,loaders 处理特定类型文件,转换成相应模块,在 bundle 前打包相应模块
Loaders需要单独安装并且需要在webpack.config.js中的modules关键字下进行配置,Loaders的配置包括以下几方面:
加载时,数组从尾部开始执行
test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)
use:[{loader,options}]
include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选)
babel
babel7 下各个子库以 - 分割,7 及之后 / 分割
pnpm install -s -d @babel/core @babel/cli @babel/preset-env @babel/preset-react
简单用法
// .babelrc
{
"presets": [
"@babel/preset-env"
]
}
// babel.config.js
module.exports = {
presets: ['@babel/preset-env']
}
npx babel .\get-package.js --out-file dist/test-babel-output.js
pnpm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader",
options: {
presets: ['@babel/preset-env']
}
},
exclude: /node_modules/
}
]
}
postCSS
通过插件系统来转换 CSS 代码,自动添加浏览器前缀,适配不同浏览器,使用未正式纳入标准的 css 语法,与其他 css 预处理语言一样变量、混合等功能
pnpm install --save-dev postcss postcss-cli autoprefixer
简单用法
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer') // 自动添加浏览器前缀
]
};
npx postcss styles.css -o build/styles.css
pnpm install --save-dev postcss-loader autoprefixer
const path = require('path');
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: 'css-loader', // 将 CSS 转换为 CommonJS 模块
options: {
importLoaders: 1, // 允许 css-loader 之前的 loaders 运行
},
},
{
loader: 'postcss-loader', // PostCSS 加载器
options: { // 已定义 PostCSS 配置文件无需配置
postcssOptions: {
plugins: [
// 自动添加浏览器前缀
require('autoprefixer')({
overrideBrowserslist: ['> 1%', 'last 2 versions', 'not dead'],
}),
// 可以添加更多 PostCSS 插件...
],
},
},
},
],
},
],
}
插件(Plugins)
插件(Plugins)是用来拓展 Webpack 功能,在整个构建过程中生效,类似于谷歌插件
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
plugins: [
new webpack.HotModuleReplacementPlugin(),// 热加载插件
new webpack.optimize.OccurrenceOrderPlugin(), // 分析和优先考虑使用最多的模块,并为它们分配最小的ID
],
npm install --save-dev extract-text-webpack-plugin
vite
依赖通过请求强缓存,源码协商缓存变化时热更新 预构建依赖,等待 HTTP 请求,构建代码,vite 充分利用缓存加快重载
打包基于 rollup,构建基于 esbuild
初始化
安装
$ npm init vite@latest
$ yarn create vite
常用命令
vite
vite build
vite preview
vite optimize
官方提供插件
// vue
import vue from '@vitejs/plugin-vue'
export default {
plugins: [vue()]
}
//vue jsx
import vueJsx from '@vitejs/plugin-vue-jsx'
export default {
plugins: [
vueJsx({
// options are passed on to @vue/babel-plugin-jsx
})
]
}
// 提供对 Vue 2.7 的单文件组件支持
import vue from '@vitejs/plugin-vue2'
export default {
plugins: [vue()]
}
// 提供对 Vue 2.7 JSX 对支持
import vueJsx from '@vitejs/plugin-vue2-jsx'
export default {
plugins: [
vueJsx({
// options are passed on to @vue/babel-preset-jsx
})
]
}
// react-Babel
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()]
})
// react-SWC
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
export default defineConfig({
plugins: [react()],
});
//babel
import legacy from '@vitejs/plugin-legacy'
export default {
plugins: [
legacy({
targets: ['defaults', 'not IE 11']
})
]
}
gulp
const { src, dest, series, parallel, task } = require('gulp');
const uglify = require('gulp-uglify'); // 用于压缩JS
const sass = require('gulp-sass')(require('sass')); // 用于编译Sass
const cleanCSS = require('gulp-clean-css'); // 用于压缩CSS
const autoprefixer = require('gulp-autoprefixer'); // 添加CSS前缀
task('pack:clean', () => {
return src(distPath, {allowEmpty: true}).pipe(gulpClean({force: true}))
})
function minifyScripts() {
return src('src/js/**/*.js') // 获取源文件
.pipe(uglify()) // 压缩JS
.pipe(dest('dist/js')); // 输出到目标目录
}
function compileSass() {
return src('src/scss/**/*.scss') // 获取Sass源文件
.pipe(sass().on('error', sass.logError)) // 编译Sass
.pipe(autoprefixer()) // 添加浏览器前缀
}
// 可以定义更多的任务,例如监听文件变化重新构建
function watchFiles() {
gulp.watch('src/js/**/*.js', minifyScripts);
gulp.watch('src/scss/**/*.scss', compileSass);
}
series.pipe(dest('dist/css')); // 输出到目标目录
// 定义默认任务(当运行`gulp`时不加任何参数时执行)
exports.default = series(parallel(minifyScripts, compileSass)); // 并行parallel或串行series执行多个任务
// 如果需要在监视模式下运行,则可以添加一个watch任务
exports.watch = series(exports.default, watchFiles);
常用命令
gulp 执行默认任务
gulp pack:clean 或者单独执行某个任务
gulp watch 若要开启文件监听模式